package com.baizw.cultivation.common.page;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

/**
 * 自定义分页
 *
 * @author 剧终1204
 * @version V1.0
 * @date 2020年04月27日 11:35
 */
@Data
@NoArgsConstructor
@ApiModel("分页参数")
public class CustomPage<T> implements IPage<T> {
    private static final long serialVersionUID = 8545996863226528798L;

    /**
     * 查询数据列表
     */
    @ApiModelProperty(value = "查询数据列表", hidden = true)
    private List<T> records = Collections.emptyList();

    /**
     * 总数
     */
    @ApiModelProperty(value = "总数", hidden = true)
    private long total = 0;
    /**
     * 每页显示条数，默认 10
     */
    @ApiModelProperty(value = "每页显示条数，默认 10", example = "10")
    private long pageSize = 10;

    /**
     * 当前页
     */
    @ApiModelProperty(value = "当前页", example = "1")
    private long pageNo = 1;

    /**
     * 排序字段信息
     */
    @JsonIgnore
    @ApiModelProperty("排序字段信息")
    private List<OrderItem> orders = new ArrayList<>();

    /**
     * 自动优化 COUNT SQL
     */
    @JsonIgnore
    @ApiModelProperty(value = "自动优化", hidden = true)
    private boolean optimizeCountSql = true;
    /**
     * 是否进行 count 查询
     */
    @JsonIgnore
    @ApiModelProperty(value = "是否进行", hidden = true)
    private boolean isSearchCount = true;
    /**
     * 是否命中count缓存
     */
    @JsonIgnore
    @ApiModelProperty(value = "是否命中count缓存", hidden = true)
    private boolean hitCount = false;

    @ApiModelProperty("状态")
    private int status;

    @ApiModelProperty("搜索关键字")
    private String search;

    /**
     * 分页构造函数
     *
     * @param pageNo 当前页
     * @param pageSize    每页显示条数
     */
    public CustomPage(long pageNo, long pageSize) {
        this(pageNo, pageSize, 0);
    }

    public CustomPage(long pageNo, long pageSize, long total) {
        this(pageNo, pageSize, total, true);
    }

    public CustomPage(long pageNo, long pageSize, boolean isSearchCount) {
        this(pageNo, pageSize, 0, isSearchCount);
    }

    public CustomPage(long pageNo, long pageSize, long total, boolean isSearchCount) {
        if (pageNo > 1) {
            this.pageNo = pageNo;
        }
        this.pageSize = pageSize;
        this.total = total;
        this.isSearchCount = isSearchCount;
    }

    /**
     * 是否存在上一页
     *
     * @return true / false
     */
    public boolean hasPrevious() {
        return this.pageNo > 1;
    }

    /**
     * 是否存在下一页
     *
     * @return true / false
     */
    public boolean hasNext() {
        return this.pageNo < this.getPages();
    }

    @Override
    public List<T> getRecords() {
        return this.records;
    }

    @Override
    public CustomPage<T> setRecords(List<T> records) {
        this.records = records;
        return this;
    }

    @Override
    public long getTotal() {
        return this.total;
    }

    @Override
    public CustomPage<T> setTotal(long total) {
        this.total = total;
        return this;
    }

    @Override
    public long getSize() {
        return this.pageSize;
    }

    @Override
    public CustomPage<T> setSize(long pageSize) {
        this.pageSize = pageSize;
        return this;
    }

    @Override
    public long getCurrent() {
        return this.pageNo;
    }

    @Override
    public CustomPage<T> setCurrent(long pageNo) {
        this.pageNo = pageNo;
        return this;
    }

    /**
     * 查找 order 中正序排序的字段数组
     *
     * @param filter 过滤器
     * @return 返回正序排列的字段数组
     */
    private String[] mapOrderToArray(Predicate<OrderItem> filter) {
        List<String> columns = new ArrayList<>(orders.size());
        orders.forEach(i -> {
            if (filter.test(i)) {
                columns.add(i.getColumn());
            }
        });
        return columns.toArray(new String[0]);
    }

    /**
     * 移除符合条件的条件
     *
     * @param filter 条件判断
     */
    private void removeOrder(Predicate<OrderItem> filter) {
        for (int i = orders.size() - 1; i >= 0; i--) {
            if (filter.test(orders.get(i))) {
                orders.remove(i);
            }
        }
    }

    /**
     * 添加新的排序条件，构造条件可以使用工厂：{@link OrderItem#build(String, boolean)}
     *
     * @param items 条件
     * @return 返回分页参数本身
     */
    public CustomPage<T> addOrder(OrderItem... items) {
        orders.addAll(Arrays.asList(items));
        return this;
    }

    /**
     * 添加新的排序条件，构造条件可以使用工厂：{@link OrderItem#build(String, boolean)}
     *
     * @param items 条件
     * @return 返回分页参数本身
     */
    public CustomPage<T> addOrder(List<OrderItem> items) {
        orders.addAll(items);
        return this;
    }

    @Override
    public List<OrderItem> orders() {
        return getOrders();
    }

    public List<OrderItem> getOrders() {
        return orders;
    }

    public void setOrders(List<OrderItem> orders) {
        this.orders = orders;
    }

    @Override
    public boolean optimizeCountSql() {
        return optimizeCountSql;
    }

    @Override
    public boolean isSearchCount() {
        if (total < 0) {
            return false;
        }
        return isSearchCount;
    }

    public CustomPage<T> setSearchCount(boolean isSearchCount) {
        this.isSearchCount = isSearchCount;
        return this;
    }

    public CustomPage<T> setOptimizeCountSql(boolean optimizeCountSql) {
        this.optimizeCountSql = optimizeCountSql;
        return this;
    }

    @Override
    public void hitCount(boolean hit) {
        this.hitCount = hit;
    }

    @Override
    public boolean isHitCount() {
        return hitCount;
    }
}
